package is.xdumper;

import is.xdumper.type.Dump;
import is.xdumper.type.ValidatorResult;
import is.xdumper.type.ValidatorResultContainer;
import is.bean.entity.department.Department;
import is.bean.entity.department.DepartmentBeanRemoteHome;
import is.bean.entity.employee.Employee;
import is.bean.entity.employee.EmployeeBeanRemoteHome;
import is.bean.entity.region.Region;
import is.bean.entity.region.RegionBeanRemoteHome;
import java.rmi.RemoteException;
import java.util.HashSet;
import java.util.Iterator;
import javax.ejb.FinderException;
import nullutil.NullUtil;

/**
 *
 * @author aspr0
 */
public class XdumperImportValidator
{
    private Dump dump;
    /**
     * Contains existing items conflicting with new ones
     */
    private Dump dumpRewrite;
    private DepartmentBeanRemoteHome departmentHome;
    private EmployeeBeanRemoteHome employeeHome;
    private RegionBeanRemoteHome regionHome;
    private ValidatorResultContainer resultContainer = new ValidatorResultContainer();

    public ValidatorResultContainer getResultContainer()
    {
        return resultContainer;
    }

    public void setDump(Dump dump)
    {
        this.dump = dump;
    }

    public void setDepartmentHome(DepartmentBeanRemoteHome departmentHome)
    {
        this.departmentHome = departmentHome;
    }

    public void setEmployeeHome(EmployeeBeanRemoteHome employeeHome)
    {
        this.employeeHome = employeeHome;
    }

    public void setRegionHome(RegionBeanRemoteHome regionHome)
    {
        this.regionHome = regionHome;
    }

    public void doValidate() throws FinderException, RemoteException
    {
        if (hasRefsValid())
        {
            if (needRewrite())
            {
                resultContainer.setResult(ValidatorResult.NEED_REWRITE);
            }
            else
            {
                resultContainer.setResult(ValidatorResult.IMPORT_READY);
            }
        }
        else
        {
            resultContainer.setResult(ValidatorResult.REFS_INVALID);
        }
    }

    private boolean hasRefsValid() throws RemoteException
    {
        if (dump.getDumpReferences())
        {
            /* Searching inside dump */
            /* Validating in-table (parent) references first */
            {
                Iterator<Department> departemnts = dump.getDepartmentTable().iterator();
                while (departemnts.hasNext())
                {
                    Department department = departemnts.next();
                    Integer dPId = department.getParentId();

                    if (NullUtil.isPositiveInteger(dPId))
                    {
                        Iterator<Department> depsLookFor = dump.getDepartmentTable().iterator();
                        boolean found = false;

                        while (depsLookFor.hasNext())
                        {
                            if (depsLookFor.next().getId().equals(dPId))
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            return false;
                        }
                    }
                }

                Iterator<Region> regions = dump.getRegionTable().iterator();
                while (regions.hasNext())
                {
                    Region region = regions.next();
                    Integer rPId = region.getParentId();

                    if (NullUtil.isPositiveInteger(rPId))
                    {
                        Iterator<Region> regsLookFor = dump.getRegionTable().iterator();
                        boolean found = false;

                        while (regsLookFor.hasNext())
                        {
                            if (regsLookFor.next().getId().equals(rPId))
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            return false;
                        }
                    }
                }
            }

            /* Validating cross-table refs */
            {
                /* Employee -> Department */
                Iterator<Employee> employees = dump.getEmployeeTable().iterator();
                while (employees.hasNext())
                {
                    Employee employee = employees.next();
                    Integer depId = employee.getDepartmentId();

                    Iterator<Department> depsLookFor = dump.getDepartmentTable().iterator();
                    boolean found = false;

                    while (depsLookFor.hasNext())
                    {
                        if (depsLookFor.next().getId().equals(depId))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        return false;
                    }
                }

                /* Department -> Boss, Department -> Region */
                Iterator<Department> departemnts = dump.getDepartmentTable().iterator();
                while (departemnts.hasNext())
                {
                    Department department = departemnts.next();
                    Integer regId = department.getRegionId();
                    Integer bossId = department.getBossId();

                    boolean found = false;
                    Iterator<Region> regsLookFor = dump.getRegionTable().iterator();
                    while (regsLookFor.hasNext())
                    {
                        if (regsLookFor.next().getId().equals(regId))
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        return false;
                    }

                    if (NullUtil.isPositiveInteger(bossId))
                    {
                        found = false;
                        Iterator<Employee> empsLookFor = dump.getEmployeeTable().iterator();
                        while (empsLookFor.hasNext())
                        {
                            if (empsLookFor.next().getId().equals(bossId))
                            {
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            return false;
                        }
                    }
                }
            }
        }
        else
        {
            /* Searching in DB */
            /* Validating in-table (parent) references first */
            {
                Iterator<Department> departemnts = dump.getDepartmentTable().iterator();
                while (departemnts.hasNext())
                {
                    Department department = departemnts.next();
                    Integer dPId = department.getParentId();

                    if (NullUtil.isPositiveInteger(dPId))
                    {
                        if (!departmentHome.entityExist(dPId))
                        {
                            return false;
                        }
                    }
                }

                Iterator<Region> regions = dump.getRegionTable().iterator();
                while (regions.hasNext())
                {
                    Region region = regions.next();
                    Integer rPId = region.getParentId();

                    if (NullUtil.isPositiveInteger(rPId))
                    {
                        if (!regionHome.entityExist(rPId))
                        {
                            return false;
                        }
                    }
                }
            }

            /* Validating cross-table refs */
            {
                /* Employee -> Department */
                Iterator<Employee> employees = dump.getEmployeeTable().iterator();
                while (employees.hasNext())
                {
                    Employee employee = employees.next();
                    Integer depId = employee.getDepartmentId();

                    if (!departmentHome.entityExist(depId))
                    {
                        return false;
                    }
                }

                /* Department -> Boss, Department -> Region */
                Iterator<Department> departemnts = dump.getDepartmentTable().iterator();
                while (departemnts.hasNext())
                {
                    Department department = departemnts.next();
                    Integer regId = department.getRegionId();
                    Integer bossId = department.getBossId();

                    boolean found = false;

                    if (regionHome.entityExist(regId))
                    {
                        found = true;
                    }

                    if (NullUtil.isPositiveInteger(bossId))
                    {
                        if (employeeHome.entityExist(bossId))
                        {
                            found = true;
                        }
                    }

                    if (!found)
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private boolean needRewrite() throws FinderException, RemoteException
    {
        boolean need = false;

        Iterator<Department> departemnts = dump.getDepartmentTable().iterator();
        Iterator<Employee> employees = dump.getEmployeeTable().iterator();
        Iterator<Region> regions = dump.getRegionTable().iterator();

        HashSet<Department> depTableRewrite = new HashSet<Department>();
        HashSet<Employee> empTableRewrite = new HashSet<Employee>();
        HashSet<Region> regTableRewrite = new HashSet<Region>();

        while (departemnts.hasNext())
        {
            int id = departemnts.next().getId();
            if (departmentHome.entityExist(id))
            {
                need = true;
                depTableRewrite.add(departmentHome.findByPrimaryKey(id).getData());
            }
        }

        while (employees.hasNext())
        {
            int id = employees.next().getId();
            if (employeeHome.entityExist(id))
            {
                need = true;
                empTableRewrite.add(employeeHome.findByPrimaryKey(id).getData());
            }
        }

        while (regions.hasNext())
        {
            int id = regions.next().getId();
            if (regionHome.entityExist(id))
            {
                need = true;
                regTableRewrite.add(regionHome.findByPrimaryKey(id).getData());
            }
        }

        if (need)
        {
            dumpRewrite = new Dump();
            dumpRewrite.setDepartmentTable(depTableRewrite);
            dumpRewrite.setEmployeeTable(empTableRewrite);
            dumpRewrite.setRegionTable(regTableRewrite);
            resultContainer.setDumpRewrite(dumpRewrite);
        }

        resultContainer.setDump(dump);

        return need;
    }
}
